﻿
#ifndef	CLIENT_SOCKET_MGR_H
#define  CLIENT_SOCKET_MGR_H

#include "MemBlockPool2.h"
#include "ClientSocket.h"
#include "ILogic.h"
#include "IEventBridge.h"

#define FRAME_FUN_THREAD_SLEEP_ELAPSE  10  // 以 ms 为单位

class GnsClientFrame 
{
public:
	friend class ClientSocket;

	enum FRAME_FUN_INTERNAL_ID	// 框架功能内部消息的 ID
	{
		 FRAME_FUN_INVALID = 0,					// 无效值
		 FRAME_FUN_DESTROY_CLIENT = 10,					// 销毁客户端
	};

	enum{
		FRAME_INTERNAL_MSG_LEN = 128,
	};

	struct FRAME_INTERNAL_MSG   // 框架功能内部消息
	{
		FRAME_INTERNAL_MSG()		{ memset(this, 0, sizeof(*this)); }

		int min2(int a, int b)
		{
			if (a > b)
				return b;
			else
				return a;
		}

		// 拷贝整个 EVENT_INFO 对象
		int copy(const  FRAME_INTERNAL_MSG& msg)
		{
			memcpy(this, &msg, sizeof(FRAME_INTERNAL_MSG));
		}

		// 拷贝包体
		int copyToBody(const char* pData, int iDataLen)
		{
			if (iDataLen > FRAME_INTERNAL_MSG_LEN)
				return 10;
			iBodyLen = min2(iDataLen, FRAME_INTERNAL_MSG_LEN);
			memcpy(szBody, pData, iBodyLen);
			return 0;
		}

		int		id;				// 框架功能内部消息的 ID，见 FRAME_FUN_INTERNAL_ID
		int		iBodyLen;
		char		szBody[FRAME_INTERNAL_MSG_LEN];
	};

	enum
	{
		CSH_ERR_WSASocket_FAIL = 10,
		CSH_ERR_is_invalid = 15,		// 无效对端
		CSH_ERR_ClientSocket_invalid = 20,	// 客户端下标值越界
		CSH_ERR_IS_INVALID_SOCKET = 30,
		CSH_ERR_CLOSE_SOCKET_FAIL = 40,
		CSH_ERR_m_pTimeQueue_is_0 = 50,
		CSH_ERR_m_hTimer_is_0 = 60,
		CSH_ERR_CreateTimerQueueTimer = 70,
		CSH_ERR_DeleteTimerQueueTimer = 80,
		CSH_ERR_CMemBlock_is_0 = 90,
		CSH_ERR_OVER_SEND_HI_WATER_MARK = 100,	// m_deqSend 超出上水位标啦
		CSH_ERR_WSASocket_fail = 110,
	};

	enum 
	{
		MAX_CLIENT_NUM = 5,		// 客户端的最大数量
	};

public:
	GnsClientFrame();
	~GnsClientFrame();

	static	GnsClientFrame* getInstance();
	static void destoryInstance();

private:

	// 创建一个 GnsClientFrame 实例
	static	GnsClientFrame* create();

public:
	virtual bool init();

	/* --------------------------------------------------------------------------
	函数说明：注册一个客户端 Socket
	传入参数：
		iClientId					客户端 Socket 的 Id
		szServerIp				服务端 IP 地址
		iPort						服务端 端口
		iMsgBlockSize		消息块的长度，默认为 1280
		bManualConnect		1 表示手工连接，需要手工调用 ClientSocket 对象的 start 函数
		0 表示自动连接，只要 GnsClientFrame 对象的 start 一执行就自动连接啦
	返回值：
		成功则返回 ClientSocket 指针，失败返回 nullptr
	-------------------------------------------------------------------------- */
	ClientSocket*  registClient(int iClientId, const char* szServerIp, int iPort, int iMsgBlockSize = 1280, int bManualConnect = 1);

	/* --------------------------------------------------------------------------
	函数说明：手动连接
	传入参数：
		iClientId					客户端 Socket 的 Id
	返回值：
		成功则返回 ClientSocket 指针，失败返回 nullptr
	-------------------------------------------------------------------------- */
	int  manualConnect(int iClientId);

	/* --------------------------------------------------------------------------
	函数说明：客户端 Socket 有效
	传入参数：
		iClientId			客户端 Socket 的 Id
	返回值：
		成功则返回 ClientSocket 指针，失败返回 nullptr
	-------------------------------------------------------------------------- */
	bool  isClientSocketValid(int iClientId);

	// 启动
	int start();

	// 获得两个数里的最小数
	static int min2(int a, int b);

	/* --------------------------------------------------------------------------
	函数说明：客户端断开并销毁客户端，注意：这是一个异步函数，直正销毁时会回调 onDestoryClient 函数
	传入参数：
		iClientId
	返回值：
		0           表示已经在断开和销毁的过程中，直正销毁时会回调 onDestoryClient 函数，
		其他值  表示错误码
	--------------------------------------------------------------------------*/
	int closeSocket(int	iClientId);

	/* --------------------------------------------------------------------------
	函数说明：发送数据
	传入参数：
		iMainCode			主码
		iSubCode			辅助码
		pData					要发送的数据
		iDataLen				要发送的数据长度
		szFunName		调用本指令时所在函数的名称，方便查错
	返回值：
		成功则返回 0，失败返回错误码
	--------------------------------------------------------------------------*/
	int sendMsg(int	iClientId,  int iMainCode, int iSubCode, char* pData, int iDataLen, char* szFunName = nullptr);

	// 设置内存块的参数
	void setMemBlock(	int iMsgBlockSize = CMemBlockPool2::DEF_MEMBLOCK_SIZE, 
										int nInitElementCount = CMemBlockPool2::DEF_INIT_COUNT,
										int nMaxElementCount = CMemBlockPool2::DEF_MAX_COUNT);

	// 设置逻辑模块
	void setLogic(ILogic* pLogic);

	/* --------------------------------------------------------------------------
	函数说明：根据客户端参数类型获得客户端参数值
	传入参数：
		iClientId			客户端 Socket 的 Id
		cpt  见  CLIENT_PARAM_TYPE
	返回值：
		成功返回正数值，失败返回 -1
	-------------------------------------------------------------------------- */
	int getParamByType(int iClientId, CLIENT_PARAM_TYPE cpt);

	// 获得客户端的数量
	int getClientNum()
	{
		return _vecClientSocket.size();
	}

private:

	// 销毁客户端，注意：这是一个异步函数，直正销毁时会回调 onDestoryClient 函数
	void destoryClient(int iClientId);

	// 销毁客户端完成后的回调
	int onDestoryClient(int iClientId);

	// 加入框架功能内部消息
	void pushFrameFunMsg(const FRAME_INTERNAL_MSG& eventInfo);

	// 停止
	int stop();

	// 框架功能的线程
	void FrameFunThread();

	// 定时器
	void timerThread();

private:
	static GnsClientFrame*  _pGnsClientFrame;

public:
	std::vector<ClientSocket*>	_vecClientSocket;

public:

	CMemBlockPool2* _pMsgPool = nullptr;			// 消息池
	ILogic*					_pLogic = nullptr;				// 逻辑模块

	int _msgBlockSize = CMemBlockPool2::DEF_MEMBLOCK_SIZE;		//  CMemBlock2 消息块的尺寸
	int _initElementCount = CMemBlockPool2::DEF_INIT_COUNT;			//  池内元素的初始数量
	int _maxElementCount = CMemBlockPool2::DEF_MAX_COUNT;		//  池内元素的最大数量

	std::thread												_timerThread;					// 定时器
	std::recursive_mutex							_mutexTimerThread;		// 递归互斥，针对 _dequeCoreMsg

	std::deque<FRAME_INTERNAL_MSG>       _dequeFrameFunMsg;	// 框架功能消息的容器
	std::thread												_frameFunThread;			// 框架功能线程
	std::recursive_mutex							_mutexFrameFun;			// 递归互斥，针对 _dequeCoreMsg

	std::atomic<bool>		m_bStart;				// 已经开始了，ture 表示 start 状态， false 表示 stop 状态
};

#endif
